﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.ServiceModel;
using System.ServiceModel.Channels;
using System.Text;
using Microsoft.ServiceBus;
using SimpleServiceBus.Bus;
using SimpleServiceBus.Bus.Transport;
using SimpleServiceBus.Endpoints.DotNetServiceBus.Utilities;

namespace SimpleServiceBus.Endpoints.DotNetServiceBus.Transport
{
    public abstract class DotNetServiceBusTransportBase : BaseTransport
    {
        public const string SsbHeaderNamespace = "http://www.simpleservicebus.com/wcf/headers/";
        
        public const string DestinationBusUserNameHeaderKey = "DotNetServiceBusUserName";
        public const string DestinationBusPasswordHeaderKey = "DotNetServiceBusPassword";
        
        public string BusSolutionName { get; set; }
        public string BusSolutionPassword { get; set; }
        
        public TimeSpan ReceiveTimeOut { get; set; }
        public TimeSpan SendTimeOut { get; set; }
       
        public override void Send(MessageEnvelope m, params string[] destinations)
        {
            foreach (string destination in destinations)
            {
                Message message = CreateWcfMessageFromMessageEnvelope(m);
                ChannelFactory<IOnewayReceiver> target = GetDestinationChannelFactoryFor(m, destination);
                try
                {
                    target.CreateChannel().Accept(message);
                    target.Close();
                }
                catch (Exception)
                {
                    target.Abort();
                    throw;
                }
            }
        }

        protected override void StartService()
        {
            base.StartService();
            
        }

        protected virtual MessageEnvelope CreateMessageEnvelopeFromWcfMessage(Message wcfMessage)
        {
            MessageEnvelope result = CreateEmptyMessageEnvelope();
            if (wcfMessage.Headers != null && wcfMessage.Headers.Count > 0)
            {
                for (int i = 0; i < wcfMessage.Headers.Count; i++)
                {
                    var info = wcfMessage.Headers[i];
                    if (info.Namespace == SsbHeaderNamespace)
                        result.Headers.Add(info.Name, wcfMessage.Headers.GetHeader<string>(info.Name, info.Namespace));
                }
            }

            result.Payload = wcfMessage.GetBody<byte[]>();
            return result;
        }

        protected virtual Message CreateWcfMessageFromMessageEnvelope(MessageEnvelope envelope)
        {
            Message message = Message.CreateMessage(MessageVersion.Default, "Accept", envelope.Payload);
            foreach (string headerKey in envelope.Headers)
            {
                message.Headers.Add(MessageHeader.CreateHeader(headerKey, SsbHeaderNamespace, envelope.Headers[headerKey]));
            }
            message.Headers.From = new EndpointAddress(ReturnAddress);
            message.Headers.ReplyTo = new EndpointAddress(ReturnAddress);
            return message;
        }

        private static ChannelFactory<IOnewayReceiver> GetDestinationChannelFactoryFor(IHeadersProvider message, string destinationAddress)
        {

            var channelFactory =
                new ChannelFactory<IOnewayReceiver>(
                    new NetOnewayRelayBinding(EndToEndSecurityMode.Transport,
                                              RelayClientAuthenticationType.RelayAccessToken),
                    new EndpointAddress(destinationAddress));

            string userName = message.Headers[DestinationBusUserNameHeaderKey];
            if (!String.IsNullOrEmpty(userName))
            {
                string password = message.Headers[DestinationBusPasswordHeaderKey];
                if (!String.IsNullOrEmpty(password))
                {
                    var credential = AzureQueueManager.CreateUsernamePasswordCredential(userName, password);
                    channelFactory.Endpoint.Behaviors.Add(credential);
                }
            }
            return channelFactory;
        }
    }
}
